/**
 * @file insidous.c fichier création interface graphique
 * @author AL RUBI M.  BONY T.  NANCY S.
 */

#include <gtk/gtk.h>
#include <glib/gprintf.h>
#include <unistd.h>
#include <time.h>

#include "projv2.h"
/** 
 * @b Buffer = la taille du nom et chemin de l'image
 */
#define buff 250 // buffer pour le nom de l'image


/** 
 * @var tableau contient les pixels de l'image1 
 */
pixel *tab1;    
/** @var tableau contient les pixels de l'image2 */
pixel *tab2;    
/** @var tableau contient les pixels de la dissimilation des images 1 et 2 */
pixel *tab3;    
/** @var tableau contient les pixels l'image dissimulée (extraction) */
pixel *tab4;    
/** @var tableau contient les pixels le résultat de l'extraction */
pixel *tab5;    
/** @var variables des dimensions des images*/
unsigned int larg1,haut1,larg2,haut2,larg3,haut3,larg4,haut4;
/** @var Variable type FILE utilisé dans le cas d'ouverture de fichier*/
FILE * monFic;
/** @var image dissim 1 */
char *image1; 
/** @var image à dissimuléé */
char *image2; 
/** @var image resultat de la dissimulation */
char *image3; 
/** @var image à extraire */
char *image4; 
/** @var image restultat extraction */
char *image5; 

 /** @brief Widget de la fenêtre de sélection des images */
GtkWidget *filew;




/**
 * @fn static int cb_show (GtkWidget * p_wid, gpointer p_data)
 * @brief fonction de la comboBox
 * Récupère le chiffer selectionné
 * @return nbBite: le nombre de bit selectionné
 */
static int cb_show (GtkWidget * p_wid, gpointer p_data)
{
	//g_printf("#cb_show\n");
	GtkComboBox 	*p_combo   = p_data;
	gchar 			*p_text    = NULL;
	int 			nbBite;
	/* mettre l'appel de la fonction de dissim / extract en passant en parametre le numero de bite choisi dans la combo*/
	p_text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (p_combo));
	nbBite=(gint) g_ascii_strtod(p_text, NULL);
	return nbBite;
}

/**
 * @fn void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
 * @brief Récupère le nom de l'image 1 au moment de la seléction de l'image, 
 * Lecture de l'entête de l'image et initialiser largeur / hauteur
 */
void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
 {
    g_printf("## file_ok_sel image1\n");
	gchar *p_text= NULL;

	image1=(char *)malloc(sizeof(char)*buff);

	p_text=gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs));
	strncpy(image1,(char *)p_text,buff-1);
	monFic=fopen(image1, "rb"); // test si on a choisi une image au bon format ou pas
	if (fgetc(monFic)!='B' || fgetc(monFic)!='M')
	{
		fclose(monFic);
		alertselImage();
	}
	else
	{
		lireEntete(image1,&larg1,&haut1);
		g_printf("--> image:%s\nhaut1 %u  larg1 %u\n",image1,haut1,larg1);
		g_printf("--> tab1 %p\n",tab1);
		//gtk_widget_destroy(w); //enlever le bouton ok
		gtk_widget_hide(filew);
	}
 }

 /**
 * @fn void file_ok_sel2 (GtkWidget *w, GtkFileSelection *fs)
 * @brief Récupère le nom de l'image 2 au moment de la seléction de l'image, 
 * Lecture de l'entête de l'image et initialiser largeur / hauteur
 */
 void file_ok_sel2 (GtkWidget *w, GtkFileSelection *fs)
 {
    g_printf("## file_ok_sel2 image2\n");
	gchar * p_text=NULL ;

    image2=(char *)malloc(sizeof(char)*buff);

	p_text=gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs));

	strncpy(image2,(char *)p_text,buff-1);
	monFic=fopen(image2, "rb"); // test si on a choisi une image au bon format ou pas
	if (fgetc(monFic)!='B' || fgetc(monFic)!='M')
	{
		fclose(monFic);
		alertselImage();
	}
	else
	{
		lireEntete(image2,&larg2,&haut2);
		g_printf("--> image:%s\nhaut2 %u  larg2 %u\n",image2,haut2,larg2);
		g_printf("--> tab2 %p\n",tab2);

		//gtk_widget_destroy(w); //enlever le bouton ok
		gtk_widget_hide(filew);
		g_printf("End file_ok_sel2 image 2\n");
	}

 }

 /**
 * @fn void file_ok_sel_extract (GtkWidget *w, GtkFileSelection *fs)
 * @brief Récupère le nom de l'image à extraire au moment de la seléction de l'image, 
 * Lecture de l'entête de l'image et initialiser largeur / hauteur
 */
 void file_ok_sel_extract (GtkWidget *w, GtkFileSelection *fs)
 {
	gchar * p_text=NULL ;

    image4=(char *)malloc(sizeof(char)*buff);

	p_text=gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs));
	
	
	strncpy(image4,(char *)p_text,buff-1);

	monFic=fopen(image4, "rb"); // test si on a choisi une image au bon format ou pas
	if (fgetc(monFic)!='B' || fgetc(monFic)!='M')
	{
		fclose(monFic);
		alertselImage();
	}
	else
	{
		lireEntete(image4,&larg4,&haut4);
		g_printf("--> image:%s\nhaut4 %u  larg4 %u\n",image4,haut4,larg4);
		g_printf("--> tab4 %p\n",tab2);


		//gtk_widget_destroy(w); //enlever le bouton ok

		gtk_widget_hide(filew);

		g_printf("End file_ok_sel_extract image extract\n");
	}

 }
 
 void freeMalloc()
 {
    //waitFor(5);
	g_printf ("## start FREE\n");
	g_printf("--> free images names\n");
	free(image1);
	free(image2);
	free(image3);

	g_printf("--> free tables\n");
	free(tab1);
	free(tab2);
	free(tab3);

	g_printf ("end FREE  \n");
 }

 /**
 * @fn void destroy (GtkWidget *widget, gpointer *data)
 * @brief Rla destriction de l'interface et fermture de l'application
 */
 void destroy (GtkWidget *widget, gpointer *data)
{
	g_printf("#destroy\n");
	freeMalloc(); // dans le cas où on ferme le programme, on libère la mémoire
	gtk_main_quit ();
	
}

 
 void selectionImage1()
 {

	//GtkWidget *filew;
	filew = gtk_file_selection_new ("Sélection Image Porteuse");

	/* Connexion de ok_button à la fonction file_ok_sel() */
	gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),"clicked", (GtkSignalFunc) file_ok_sel, filew );

	/* Connexion de cancel_button pour détruire le widget */
	gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),"clicked", (GtkSignalFunc) gtk_widget_destroy,GTK_OBJECT (filew));

	gtk_widget_show(filew);

 }

 void selectionImage2()
{

	filew = gtk_file_selection_new ("Sélection Image à Dissimuler");

	/* Connexion de ok_button à la fonction file_ok_sel2() */
	gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),"clicked", (GtkSignalFunc) file_ok_sel2, filew );

	/* Connexion de cancel_button pour détruire le widget */
	gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),"clicked", (GtkSignalFunc) gtk_widget_destroy,GTK_OBJECT (filew));

	gtk_widget_show(filew);

}
void affichConfDissim()
{
    GtkWidget *p_dialog = NULL;
    gchar p_msg[256]="Dissimulation terminée !";
    int ret_val;
    gchar * s_utf8 = NULL;
    s_utf8 = g_locale_to_utf8 (p_msg, -1, NULL, NULL, NULL);


   /* Creation de la boite de message. */
   p_dialog = gtk_message_dialog_new (
                  NULL,
                  GTK_DIALOG_MODAL,
                  GTK_MESSAGE_INFO,
                  GTK_BUTTONS_OK,
                  s_utf8,NULL,
                  GTK_RESPONSE_CLOSE);
     ret_val = gtk_dialog_run (GTK_DIALOG (p_dialog));
	 if (ret_val != NULL)
		 gtk_widget_hide(p_dialog);
	 

}

void affichConfExtract()
{
    GtkWidget *p_dialog = NULL;
    gchar p_msg[256]="Extraction terminée !";
    int ret_val;
    gchar * s_utf8 = NULL;
    s_utf8 = g_locale_to_utf8 (p_msg, -1, NULL, NULL, NULL);

   p_dialog = gtk_message_dialog_new (
                  NULL,
                  GTK_DIALOG_MODAL,
                  GTK_MESSAGE_INFO,
                  GTK_BUTTONS_OK,
                  s_utf8,NULL,
                  GTK_RESPONSE_CLOSE);
     ret_val = gtk_dialog_run (GTK_DIALOG (p_dialog));
	 
	  if (ret_val != NULL)
		 gtk_widget_hide(p_dialog);

}

void alertDissim()
{
    GtkWidget *p_dialog = NULL;
    gchar p_msg[256]="Veuillez choisir 2 images valides !!! ";
    int ret_val;
    gchar * s_utf8 = NULL;
    s_utf8 = g_locale_to_utf8 (p_msg, -1, NULL, NULL, NULL);

   p_dialog = gtk_message_dialog_new (
                  NULL,
                  GTK_DIALOG_MODAL,
                  GTK_MESSAGE_ERROR,
                  GTK_BUTTONS_OK,
                  s_utf8,NULL,
                  GTK_RESPONSE_CLOSE);
     ret_val = gtk_dialog_run (GTK_DIALOG (p_dialog));
	 
	  if (ret_val != NULL)
		 gtk_widget_hide(p_dialog);

}

void alertExtract()
{
    GtkWidget *p_dialog = NULL;
    gchar p_msg[256]="Veuillez choisir une image dissimulée !!! ";
    int ret_val;
    gchar * s_utf8 = NULL;
    s_utf8 = g_locale_to_utf8 (p_msg, -1, NULL, NULL, NULL);

   p_dialog = gtk_message_dialog_new (
                  NULL,
                  GTK_DIALOG_MODAL,
                  GTK_MESSAGE_ERROR,
                  GTK_BUTTONS_OK,
                  s_utf8,NULL,
                  GTK_RESPONSE_CLOSE);
     ret_val = gtk_dialog_run (GTK_DIALOG (p_dialog));
	 
	  if (ret_val != NULL)
		 gtk_widget_hide(p_dialog);

}

void alertselImage()
{
    GtkWidget *p_dialog = NULL;
    gchar p_msg[256]="Veuillez choisir une image !!! ";
    int ret_val;
    gchar * s_utf8 = NULL;
    s_utf8 = g_locale_to_utf8 (p_msg, -1, NULL, NULL, NULL);

   p_dialog = gtk_message_dialog_new (
                  NULL,
                  GTK_DIALOG_MODAL,
                  GTK_MESSAGE_ERROR,
                  GTK_BUTTONS_OK,
                  s_utf8,NULL,
                  GTK_RESPONSE_CLOSE);
     ret_val = gtk_dialog_run (GTK_DIALOG (p_dialog));
	 
	  if (ret_val != NULL)
		 gtk_widget_hide(p_dialog);

}
/**
 * @fn void dissimulationImage(GtkWidget * p_wid, gpointer p_data)
 * @brief Fonction effectue l'opération de la dissimulation
 */
void dissimulationImage(GtkWidget * p_wid, gpointer p_data)
{
    g_printf("## dissimulationImage\n");
	int nbBite=2;
	nbBite=cb_show(p_wid,p_data);
	/* Allocation tab contient image dissimulée */
    g_printf("--> haut1 %u  larg1 %u\n",haut1,larg1);
    g_printf("--> haut2 %u  larg2 %u\n",haut2,larg2);
	
	if( (haut1==0) || (larg1==0) || (haut2==0) || (larg2==0) )
	{
		alertDissim();
	}
	
	else
	{
		tab1	=	(pixel *)malloc(sizeof(pixel)*haut1*larg1);
		tab2	=	(pixel *)malloc(sizeof(pixel)*haut2*larg2);
		tab3	=	(pixel *)malloc(sizeof(pixel)*haut1*larg1);
		image3=(char *)malloc(sizeof(char)*buff);
		image3="dissimGtk.bmp";

		g_printf("#dissimulationImage	tab1	%p	%s\n",tab1,image1);
		g_printf("#dissimulationImage	tab2	%p	%s\n",tab2,image2);
		g_printf("#dissimulationImage	tab3	%p	%s\n",tab3,image3);

		remplirTableauPixelsDepuisFichier(image1, tab1, larg1, haut1);
		remplirTableauPixelsDepuisFichier(image2, tab2, larg2, haut2);

		dissimulation(tab1,tab2,tab3,larg1,haut1,nbBite);
		ecrireFichier(image3, tab3, larg1, haut1);

		g_printf ("fin ecrireFichier\n");

		affichConfDissim();
	}
	

}
void selectionImageExtract()
{
    g_printf("in selectionImageExtract\n");
	//GtkWidget *filew;
	filew = gtk_file_selection_new ("Sélection image à Extraire");

	/* Connexion de ok_button à la fonction file_ok_sel() */
	gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),"clicked", (GtkSignalFunc) file_ok_sel_extract, filew );

	/* Connexion de cancel_button pour détruire le widget */
	gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),"clicked", (GtkSignalFunc) gtk_widget_destroy,GTK_OBJECT (filew));

	gtk_widget_show(filew);
}


/**
 * @fn void extractionImage(GtkWidget * p_wid, gpointer p_data)
 * @brief Fonction extraction de l'image dissimuléé 
 */
 void extractionImage(GtkWidget * p_wid, gpointer p_data)
{
	g_printf("## extractionImage\n");
	int nbBite=2;
	nbBite=cb_show(p_wid,p_data);

    g_printf("--> haut4 %u  larg4 %u\n",haut4,larg4);
	
	if ( (haut4 ==0) || (larg4==0))
	{
		alertExtract();
	}
	else
	{
		
		/** Allocation tab contient l'image de la dissimulation et image res extraction */
		tab4	=	(pixel *)malloc(sizeof(pixel)*haut4*larg4);
		tab5	=	(pixel *)malloc(sizeof(pixel)*haut4*larg4);

		image5=(char *)malloc(sizeof(char)*buff);
		image5="extractGtk.bmp";

		g_printf("#extractionImage	tab4	%p	%s\n",tab4,image4);
		g_printf("#extractionImage	tab5	%p	%s\n",tab5,image5);

		remplirTableauPixelsDepuisFichier(image4, tab4, larg4, haut4);

		extraction(tab4,tab5,larg4,haut4,nbBite);

		ecrireFichier(image5, tab5, larg4, haut4);

		g_printf ("fin ecrireFichier extract  \n");
		affichConfExtract();
	}


}
void waitFor (unsigned int secs)
{
    unsigned int retTime = time(0) + secs;      // Get finishing time.
    while (time(0) < retTime);                  // Loop until it arrives.
}
 
int main (int argc, char ** argv)
{
	g_printf("in main\n");
	GtkWidget * p_win 		= NULL;

	GtkWidget * p_vbox 		= NULL;
	GtkWidget * p_button[5];
	GtkWidget * p_combo		= NULL;
	GtkWidget * label     	= NULL;
	GtkWidget * label2    	= NULL;
	GtkWidget * label3    	= NULL;



	image1=(char *)malloc(sizeof(char)*buff);
	image2=(char *)malloc(sizeof(char)*buff);
	image3=(char *)malloc(sizeof(char)*buff);
	image4=(char *)malloc(sizeof(char)*buff);
	image5=(char *)malloc(sizeof(char)*buff);

	gtk_init (& argc, & argv);


	/**
	* Creation de la fenetre principale.
	*/
	p_win = gtk_window_new           (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title             (GTK_WINDOW (p_win), "INSIDOUS ©");
	gtk_window_set_default_size      (GTK_WINDOW (p_win), 400, 150);
	gtk_container_set_border_width   (GTK_CONTAINER (p_win), 5);
	gtk_window_set_position          (GTK_WINDOW (p_win), GTK_WIN_POS_CENTER);
	/** affectation label pour le choix de bits */
	label = gtk_label_new ("Choisir le nombre de bits à traiter dans chaque pixel:");
	/** label Dissimulation/Extraction*/
	label2 = gtk_label_new ("Opération Dissimulation:");
	label3 = gtk_label_new ("Opération Extraction:");
	/* Ajout du conteneur principal et des boutons. */
	p_vbox = gtk_vbox_new   (TRUE, 0);
	gtk_container_add       (GTK_CONTAINER (p_win), p_vbox);
	/* selection fichier */

	/** GESTION LABEL DISSIMULATION
	*/

	gtk_misc_set_alignment (GTK_MISC (label2), 0, 0);
	gtk_box_pack_start (GTK_BOX (p_vbox), label2, FALSE, FALSE, 0);
	/** Affichage du label */
	gtk_widget_show (label2);


	p_button[1] = gtk_button_new_with_label ("Choisir l'image porteuse");
	gtk_box_pack_start (GTK_BOX (p_vbox), p_button[1], TRUE, FALSE, 0);

	p_button[2] = gtk_button_new_with_label ("Choisir l'image à dissimuler");
	gtk_box_pack_start (GTK_BOX (p_vbox), p_button[2], TRUE, FALSE, 0);
	
	p_button[0] = gtk_button_new_with_label ("Dissimulation");
	gtk_box_pack_start (GTK_BOX (p_vbox), p_button[0], FALSE, FALSE, 0);

	

		/** GESTION LABEL EXTRACTION
	*/
	gtk_misc_set_alignment (GTK_MISC (label3), 0, 0);
	gtk_box_pack_start (GTK_BOX (p_vbox), label3, FALSE, FALSE, 0);
	/** Affichage du label */
	gtk_widget_show (label3);
	
	p_button[4] = gtk_button_new_with_label ("Choisir l'image à extraire");
	gtk_box_pack_start (GTK_BOX (p_vbox), p_button[4], TRUE, FALSE, 0);
	
	p_button[3] = gtk_button_new_with_label ("Extraction");
	gtk_box_pack_start (GTK_BOX (p_vbox), p_button[3], TRUE, FALSE, 0);

	

	/** GESTION LABEL CHOIX BIT
	* Creation d'un GtkComboBox predefinit et ajout dans le conteneur.
	*/
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0);

	/* Placement du label dans la boîte verticale (vbox box1). Il ne
	* faut pas oublier que les widgets qui s'ajoutent à une vbox sont
	* placés les uns au dessus des autres. */

	gtk_box_pack_start (GTK_BOX (p_vbox), label, FALSE, FALSE, 0);
	/** Affichage du label */
	gtk_widget_show (label);


	p_combo = gtk_combo_box_new_text ();
	gtk_box_pack_end (GTK_BOX (p_vbox), p_combo, TRUE, FALSE, 0);


	/**
	* Insertion de donnees dans la liste du widget.
	*/
	gtk_combo_box_append_text  (GTK_COMBO_BOX (p_combo), "2");
	gtk_combo_box_append_text  (GTK_COMBO_BOX (p_combo), "3");
	gtk_combo_box_append_text  (GTK_COMBO_BOX (p_combo), "4");
	gtk_combo_box_append_text  (GTK_COMBO_BOX (p_combo), "5");
	gtk_combo_box_append_text  (GTK_COMBO_BOX (p_combo), "6");
	gtk_combo_box_append_text (GTK_COMBO_BOX (p_combo), "7");

	/**
	* On affiche un element par defaut. L'index commence à zero.
	*/
	gtk_combo_box_set_active (GTK_COMBO_BOX (p_combo), 0);

	/**
	* On definit les callback :
	*/

	g_signal_connect (
		G_OBJECT (p_win), "destroy", G_CALLBACK (gtk_main_quit), NULL
	);
	g_signal_connect (
		G_OBJECT (p_button[0]), "clicked", G_CALLBACK (dissimulationImage), p_combo
	); // dissimulation
	g_signal_connect (
		G_OBJECT (p_button[1]), "clicked", G_CALLBACK (selectionImage1), p_combo
	);// image 1

	g_signal_connect (
		G_OBJECT (p_button[2]), "clicked", G_CALLBACK (selectionImage2), p_combo
	); // image 2

	g_signal_connect (
		G_OBJECT (p_button[3]), "clicked", G_CALLBACK (extractionImage), p_combo
	); // extraction

	g_signal_connect (
		G_OBJECT (p_button[4]), "clicked", G_CALLBACK (selectionImageExtract), p_combo
	); // image à extraire
	gtk_widget_show_all (p_win);
	gtk_main ();


	return 0;
}
